/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#ifndef __XOS_STL_ASYNC_LOG_ASYNC_LOG_H__
#define __XOS_STL_ASYNC_LOG_ASYNC_LOG_H__

#include <iostream>
#include <sstream>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <typeinfo>
#include <cstring>
#include <list>

namespace xos_container
{
    class i_container;
}
namespace xos_log
{
    class i_log_msg;
    class i_log_mgr;
}
namespace xos_box
{
    class i_box_mgr;
    class i_string;
    class i_list;
}
namespace xos
{
    class i_crt;
}

namespace xos_stl
{
    namespace async_log
    {
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 

        template<typename... Args>
        class xos_async_log
        {
        public:
            using TupleType = std::tuple<std::decay_t<Args>...>;

        public:
            xos_async_log()
            {
            }
            ~xos_async_log()
            {
            }

        public:
            // 
            // 检测是否为需要深拷贝的字符串类型
            // 
            template <typename T>
            struct is_cstring_base 
            {
                using raw_type = typename std::remove_reference< typename std::remove_cv<T>::type>::type;

                static constexpr bool value = std::is_pointer<raw_type>::value && std::is_same<typename std::remove_cv< typename std::remove_pointer<raw_type>::type >::type, char>::value;
            };

            template <typename T>
            struct is_cstring : is_cstring_base<T> {};

        public:

            // 递归深拷贝实现
            template <size_t Index = 0>
            typename std::enable_if<Index == sizeof...( Args )>::type
                go_through_and_deep_copy_strings( xos_box::i_box_mgr * pBox, xos_box::i_list * pList, TupleType & )
            {
            }

            template <size_t Index = 0>
            typename std::enable_if < Index < sizeof...( Args )>::type
                go_through_and_deep_copy_strings( xos_box::i_box_mgr * pBox, xos_box::i_list * pList, TupleType & t )
            {
                using CurrentType = typename std::tuple_element<Index, TupleType >::type;
                /*
                {
                    // 使用改进的类型检测
                    using raw_type = typename std::remove_reference<
                        typename std::remove_cv<CurrentType>::type>::type;

                    bool is_ptr = std::is_pointer<raw_type>::value;
                    bool is_char = std::is_same<typename std::remove_cv<
                        typename std::remove_pointer<raw_type>::type
                    >::type, char>::value;

                    const char * lpszType = typeid( CurrentType ).name();
                    bool bRet = is_ptr && is_char;

                    printf( "arg type = %s, raw = %s, is_ptr=%d, is_char=%d, bRet=%d\r\n",
                        lpszType,
                        typeid( raw_type ).name(),
                        is_ptr,
                        is_char,
                        bRet );
                }
                */
                // SFINAE分支选择
                copy_if_cstring<CurrentType>( pBox, pList, std::get<Index>( t ) );
                // 递归处理下一个元素
                go_through_and_deep_copy_strings<Index + 1>( pBox, pList, t );
            }

            // 对字符串类型执行深拷贝
            template <typename T>
            typename std::enable_if<is_cstring<T>::value>::type
                copy_if_cstring( xos_box::i_box_mgr * pBox, xos_box::i_list * pList, T & ptr )
            {
                using RawType = typename std::remove_cv<T>::type;
                RawType & pszStr = const_cast<RawType &>( ptr );
                if( !pszStr )
                {
                    pszStr = (char*)"";
                    return;
                }
                xos_box::i_string * pStr = pBox->string();
                pStr->set( pszStr );
                pList->push_back( pStr );
                pszStr = (char *)pStr->get( 0, 0 );
                //printf( "old = 0x%p, new = 0x%p\r\n", pOldPtr, pszStr );
            }

            // 非字符串类型跳过
            template <typename T>
            typename std::enable_if<!is_cstring<T>::value>::type
                copy_if_cstring( xos_box::i_box_mgr * pBox, xos_box::i_list * pList, T & ptr )
            {
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // 

            template <typename Tuple, size_t... Is>
            void printf_args_impl( xos::i_crt * pCrt, xos_box::i_string * pStr, const char * fmt, const Tuple & t, std::index_sequence<Is...> )
            {
                pCrt->sprintf( pStr, fmt, std::get<Is>( t )... );
                //printf( fmt, std::get<Is>( t )... );
            }

            void printf_args( xos::i_crt * pCrt, xos_box::i_string * pStr, const char * fmt, const TupleType & t )
            {
                printf_args_impl( pCrt, pStr, fmt, t, std::make_index_sequence<sizeof...( Args )>{} );
            }

        };

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 

        template <typename... Args>
        void log( xos_container::i_container * pContainer,
            const char * lpszName, int ulLevel, const char * lpszCodeFile, int ulCodeLine, 
            const char * lpszFmt, Args&&...args )
        {
            using TupleType = std::tuple<std::decay_t<Args>...>;
            xos_box::i_box_mgr * pBox = pContainer->box();
            xos_log::i_log_mgr * pLog = pContainer->log();
            xos_log::i_log_msg * pMsg = pLog->msg();
            {
                TupleType * pArgs = 0;
                pMsg->set_log_info( lpszName, ulLevel, lpszCodeFile, ulCodeLine, lpszFmt );
                {
                    char * lpszArgsBuf = pMsg->args_buf();
                    pArgs = (TupleType *)lpszArgsBuf;
                    new ( pArgs ) TupleType( std::forward<Args>( args )... );
                }
                {
                    xos_box::i_list * pList = pMsg->str_args_list();
                    xos_async_log<Args...> obj;
                    obj.go_through_and_deep_copy_strings( pBox, pList, *pArgs );
                }
            }
            xos_log::f_log_destroy f_destroy = 0;
            xos_log::f_log_fmt_args f_fmt = 0;
            {
                auto f = []( xos_container::i_container * pContainer, xos_log::i_log_msg * pMsg, xos_box::i_string * pStr )
                {
                    xos::i_crt * pCrt = pContainer->crt();
                    const char * fmt = pMsg->get_fmt();
                    char * lpszArgsBuf = pMsg->args_buf();
                    TupleType * pArgs = (TupleType *)lpszArgsBuf;
                    {
                        xos_async_log<Args...> obj;
                        obj.printf_args( pCrt, pStr, fmt, *pArgs );
                    }
                };
                f_fmt = static_cast<xos_log::f_log_fmt_args>( f );
            }
            {
                auto f = []( char * lpszArgs )
                {
                    TupleType * pArgs = (TupleType *)lpszArgs;
                    pArgs->~TupleType();
                };
                f_destroy = static_cast<xos_log::f_log_destroy>( f );
            }
            {
                pMsg->set_destroy_fun( f_destroy );
                pMsg->set_fmt_log_fun( f_fmt );
                pLog->notify( pMsg );
            }
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //


    } // async_log

} // xos_stl

#endif // __XOS_STL_ASYNC_LOG_ASYNC_LOG_H__
